package pl.enigmatic.util;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.JPanel;


public class Printer {

	private final static Map<Class<?>, Printer> printers = new HashMap<Class<?>, Printer>();

	public static Printer get(Class<?> cls) {
		if (!printers.containsKey(cls)) {
			printers.put(cls, new Printer(cls));
		}
		return printers.get(cls);
	}

	public static Printer get(Object obj) {
		return get(obj.getClass());
	}

	private final Class<?> clazz;
	private final Printer parent;
	private final Map<String, Method> getters = new HashMap<String, Method>();

	private Printer(Class<?> cls) {
		this.clazz = cls;
		cls = clazz.getSuperclass();
		parent = cls == null ? null : get(cls);
		getters.putAll(Reflection.getDeclaredGetters(clazz));
	}

	public Class<?> getClazz() {
		return clazz;
	}

	public Printer getParent() {
		return parent;
	}

	public boolean hasParent() {
		return parent != null;
	}

	private String convert(Object obj, int indent) {
		if (obj == null) return null;
		StringBuilder builder = new StringBuilder();
		if (hasParent()) {
			builder.append(parent.convert(obj, indent));
		}
		String tabs = Strings.repeat("\t", indent);
		for (Entry<String, Method> property : getters.entrySet()) {
			builder.append(tabs);
			builder.append(property.getKey());
			builder.append(" = ");
			try {
				Object val = property.getValue().invoke(obj);
				builder.append(obj == null ? null : get(obj.getClass()).convert(val));
			} catch (Exception e) {}
			builder.append("\n");
		}
		return builder.toString();
	}

	public String convert(Object obj) {
		return convert(obj, 0);
	}

	public static void main(String[] args) {
		Object obj = new JPanel();
		Printer printer = get(obj);
		System.out.println(printer.convert(obj));
	}

}
